package python

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
)

const (
	pyExt = ".py"
)

type Python struct {
	BinPath string
	Ext     string
	Envs    []string
}

type Option func(*Python)

func WithExt(ext string) Option {
	return func(p *Python) {
		p.Ext = ext
	}
}

func WithEnvs(envs ...string) Option {
	return func(p *Python) {
		p.Envs = envs
	}
}

func New(pythonFile string, options ...Option) *Python {
	binPathAbs, _ := filepath.Abs(pythonFile)
	p := &Python{
		BinPath: binPathAbs,
		Ext:     pyExt,
	}
	for _, option := range options {
		option(p)
	}
	return p
}

func (p *Python) ExecCtx(ctx context.Context, codeDir, pyFile string, args ...string) error {
	cmd := exec.CommandContext(ctx, p.BinPath, append([]string{fmt.Sprintf("%s%s", pyFile, p.Ext)}, args...)...)
	cmd.Dir = codeDir
	cmd.Env = p.Envs
	errContext := new(bytes.Buffer)
	errContext.WriteString(fmt.Sprintf("cmd: [ %s ]\n", cmd.String()))
	cmd.Stderr = io.MultiWriter(errContext, os.Stderr)
	cmd.Stdout = io.MultiWriter(errContext, os.Stdout)
	err := cmd.Run()
	if err != nil {
		err = errors.New(errContext.String() + "\n\n" + err.Error())
	}
	return err
}
